from django.core.exceptions import ValidationError
from django.http import Http404
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin

from . import models
from .models import Book, Author, BookInstance, Genre
from django.contrib.auth.decorators import login_required
def index(request):
    """
    View function for home page of site.
    """
    # Generate counts of some of the main objects
    num_books=Book.objects.all().count()
    num_instances=BookInstance.objects.all().count()
    # Available books (status = 'a')
    num_instances_available=BookInstance.objects.filter(status__exact='a').count()
    num_authors=Author.objects.count()  # The 'all()' is implied by default.

    # Number of visits to this view, as counted in the session variable.
    num_visits = request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits + 1

    # Render the HTML template index.html with the data in the context variable
    return render(
        request,
        'index.html',
        context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors,
            'num_visits':num_visits}, # num_visits appended
    )
from django.views import generic, View


class BookListView(generic.ListView):
    model = Book
    paginate_by = 2

class BookDetailView(generic.DetailView):
    model = Book

def book_detail_view(request,pk):
    try:
        book_id=Book.objects.get(pk=pk)
    except Book.DoesNotExist:
        raise Http404("Book does not exist")

    #book_id=get_object_or_404(Book, pk=pk)

    return render(
        request,
        'catalog/book_detail.html',
        context={'book':book_id,}
    )



from django.contrib.auth.mixins import LoginRequiredMixin
class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
    """
    Generic class-based view listing books on loan to current user.
    """
    model = BookInstance
    template_name ='catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10

    def get_queryset(self):
        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')

    from django.contrib.auth.decorators import permission_required

    @permission_required('catalog.can_mark_returned')
    @permission_required('catalog.can_edit')
    @login_required
    def my_view(request):
        class MyView(LoginRequiredMixin, View):
            login_url = '/login/'
            redirect_field_name = 'redirect_to'

    from django.contrib.auth.mixins import PermissionRequiredMixin

    class MyView(PermissionRequiredMixin, View):
        permission_required = 'catalog.can_mark_returned'
        # Or multiple permissions
        permission_required = ('catalog.can_mark_returned', 'catalog.change_book')
        # Note that 'catalog.change_book' is permission
        # Is created automatically for the book model, along with add_book, and delete_book

import datetime

from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse

from catalog.forms import RenewBookForm

@login_required
@permission_required('catalog.can_mark_returned', raise_exception=True)
def renew_book_librarian(request, pk):
    """View function for renewing a specific BookInstance by librarian."""
    book_instance = get_object_or_404(BookInstance, pk=pk)

    # If this is a POST request then process the Form data
    if request.method == 'POST':

        # Create a form instance and populate it with data from the request (binding):
        form = RenewBookForm(request.POST)

        # Check if the form is valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
            book_instance.due_back = form.cleaned_data['renewal_date']
            book_instance.save()

            # redirect to a new URL:
            return HttpResponseRedirect(reverse('all-borrowed'))

    # If this is a GET (or any other method) create the default form.
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date})

    context = {
        'form': form,
        'book_instance': book_instance,
    }

    return render(request, 'catalog/book_renew_librarian.html', context)

from django.forms import ModelForm

from catalog.models import BookInstance

class RenewBookModelForm(ModelForm):
    def clean_due_back(self):
       data = self.cleaned_data['due_back']

       # Check if a date is not in the past.
       if data < datetime.date.today():
           raise ValidationError(_('Invalid date - renewal in past'))

       # Check if a date is in the allowed range (+4 weeks from today).
       if data > datetime.date.today() + datetime.timedelta(weeks=4):
           raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))

       # Remember to always return the cleaned data.
       return data

    class Meta:
        model = BookInstance
        fields = ['due_back']
        labels = {'due_back':('Renewal date')}
        help_texts = {'due_back':('Enter a date between now and 4 weeks (default 3).')}

from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Author

class AuthorCreate(PermissionRequiredMixin, CreateView):
    model = Author
    fields = ['first_name', 'last_name', 'date_of_birth', 'date_of_death']
    initial = {'date_of_death': '11/11/2023'}
    permission_required = 'catalog.add_author'

class AuthorUpdate(PermissionRequiredMixin, UpdateView):
    model = Author
    # Not recommended (potential security issue if more fields added)
    fields = '__all__'
    permission_required = 'catalog.change_author'

class AuthorDelete(PermissionRequiredMixin, DeleteView):
    model = Author
    success_url = reverse_lazy('authors')
    permission_required = 'catalog.delete_author'

    def form_valid(self, form):
        try:
            self.object.delete()
            return HttpResponseRedirect(self.success_url)
        except Exception as e:
            return HttpResponseRedirect(
                reverse("author-delete", kwargs={"pk": self.object.pk})
            )

from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView
from .models import BookInstance

class AllBorrowedListView(PermissionRequiredMixin, ListView):
    """
    视图：显示所有被借出的书籍（仅限管理员）
    """
    model = BookInstance
    template_name = 'catalog/bookinstance_list_all_borrowed.html'
    permission_required = 'catalog.can_mark_returned'  # 需要管理员权限
    paginate_by = 10  # 每页显示10条记录

    def get_queryset(self):
        # 过滤状态为 'o'（借出）的书籍，并按归还日期排序
        return BookInstance.objects.filter(status__exact='o').order_by('due_back')


from django.views.generic import ListView
from .models import Author


class AuthorListView(ListView):
    """视图：显示所有作者的列表"""
    model = Author  # 关联Author模型
    template_name = 'catalog/author_list.html'  # 模板路径
    context_object_name = 'author_list'  # 模板中使用的变量名
    paginate_by = 10  # 每页显示10条记录

    def get_queryset(self):
        """可自定义查询逻辑（如排序）"""
        return Author.objects.order_by('last_name', 'first_name')

from django.views.generic import DetailView
from .models import Author  # 导入 Author 模型，需根据实际模型位置调整

class AuthorDetailView(DetailView):
    """
    作者详细视图，用于展示单个作者的详细信息
    """
    model = Author  # 关联 Author 模型，自动从 URL 中获取 pk 并查询对应作者数据
    template_name = 'catalog/author_detail.html'  # 渲染使用的模板文件路径
    context_object_name = 'author'  # 传递到模板中的变量名，模板里用 {{ author }} 访问作者对象


# catalog/views.py
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView
from .models import BookInstance


class AllBorrowedListView(PermissionRequiredMixin, ListView):
    """仅图书馆员可见的借阅列表视图"""
    model = BookInstance
    template_name = 'catalog/all_borrowed.html'
    permission_required = 'catalog.can_mark_returned'  # 关联权限
    paginate_by = 10  # 分页

    def get_queryset(self):
        # 只显示 "已借出" 状态的书籍
        return BookInstance.objects.filter(status__exact='o').order_by('due_back')

# catalog/views.py
from django.views.generic import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.urls import reverse_lazy
from .models import Book
from .forms import BookCreateForm, BookUpdateForm, BookDeleteForm

class BookCreateView(PermissionRequiredMixin, CreateView):
    """创建书籍的视图（需权限）"""
    permission_required = 'catalog.add_book'  # 需要添加书籍的权限
    model = Book
    form_class = BookCreateForm
    template_name = 'catalog/book_form.html'
    success_url = reverse_lazy('books')  # 成功后重定向到书籍列表

class BookUpdateView(PermissionRequiredMixin, UpdateView):
    """编辑书籍的视图（需权限）"""
    permission_required = 'catalog.change_book'  # 需要修改书籍的权限
    model = Book
    form_class = BookUpdateForm
    template_name = 'catalog/book_form.html'
    success_url = reverse_lazy('books')

class BookDeleteView(PermissionRequiredMixin, DeleteView):
    """删除书籍的视图（需权限）"""
    permission_required = 'catalog.delete_book'  # 需要删除书籍的权限
    model = Book
    template_name = 'catalog/book_confirm_delete.html'
    success_url = reverse_lazy('books')